package diamondServer.businesslogic.manager;

import java.io.File;
import java.net.MalformedURLException;
import java.util.Set;

import org.apache.log4j.Logger;
import org.xml.sax.SAXException;

import diamondServer.businesslogic.configs.ResourceDataReader;
import diamondServer.businesslogic.configs.XMLResourceDataReader;
import diamondServer.businesslogic.parser.ParseException;
import diamondServer.businesslogic.parser.Parser;
import diamondServer.businesslogic.parser.ParserFake;
import diamondServer.businesslogic.resource.DefaultResRepository;
import diamondServer.businesslogic.resource.Resource;
import diamondServer.businesslogic.resource.ResourceData;
import diamondServer.businesslogic.resource.ResourcesRepository;
import diamondServer.businesslogic.resource.loader.URLResourceLoader;
import diamondServer.businesslogic.router.DefaultRouter;
import diamondServer.businesslogic.router.Router;
import diamondServer.businesslogic.router.RouterException;
import diamondServer.resources.Message;



/**
 * Thread safe Business Logic Manager
 */
public class DefaultBLManager
	implements BusinessLogicManager
{
	private final Parser mParser;
	private final Router mRouter;
	private final URLResourceLoader mResLoader;
	private final ResourcesRepository mResRepository;
	private static final Logger log = 
		Logger.getLogger(DefaultBLManager.class);	
	
	private static DefaultBLManager 
		mInstance = new DefaultBLManager();
	
	private DefaultBLManager() 
	{
		mResRepository = DefaultResRepository.getInstance();
		mParser = new ParserFake(mResRepository);
		mRouter = new DefaultRouter(mResRepository);
		URLResourceLoader notFinalLoader = null;
		try {
			notFinalLoader = new URLResourceLoader();
		} catch (MalformedURLException e) {
			log.error("resource loader couldn't find the path to resources",e);
		}
		mResLoader = notFinalLoader;
		
		runResourcesReader();
	}
	
	/**
	 * reads by infinite loop what resources are available to the server
	 * and updates the server.
	 */
	private void runResourcesReader(){
		File xmlFile = new File("resources.xml");
		ResourceDataReader xmlReader;
		try {
			xmlReader = new XMLResourceDataReader(xmlFile);
		} catch (SAXException e) {
			log.error("xml file reading error",e);
			return;
		}
		Thread readerThread = new Thread(new ReaderRunner(xmlReader,this));
		readerThread.setName("Thread-XmlReader");
		readerThread.setDaemon(true);
		readerThread.setPriority(Thread.MIN_PRIORITY);
		readerThread.start();
	}
	
	public static DefaultBLManager getInstance()
	{
		return mInstance;
	}
	
	@Override
	public void process(String sMessage)
	{
		log.info("processing the message: " + sMessage);
		Message msg;
		
		log.debug("parsing..");
		try {
			msg = mParser.parse(sMessage);
		} catch (ParseException e) {
			log.warn(e.getMessage());
			return;
		}
		log.debug("was parsed");
		
		log.debug("routing..");
		try {
			mRouter.route(msg);
		} catch (RouterException e) {
			log.warn("router exception",e);
			return;
		}
		
		log.debug("was routed");
		log.info("the message " + sMessage +" was processed");
	}

	/**
	 * For all resource to be updated:
	 * <ol>
	 * 	<li> loads the resource by ClassLoader </li>
	 *  <li> adds the resource to the {@link ResourcesRepository} </li>
	 * </ol>
	 */
	@Override
	public void updateResources(Set<ResourceData> resourcesData)
	{
		for(ResourceData resData : resourcesData){
			log.info("loads the resource " + resData);
			
			/* loads the resource */
			Resource resource;
			try {
				resource = mResLoader.load(resData.getMessageClassName(),
						resData.getServiceClassName());
			} catch (Exception e) {
				log.warn("could not load the " + e.getMessage());
				continue;
			}
			
			/* adds it to the repository */
			mResRepository
				.addResource(resource.getMessage().getResourceName(), resource);
			
			log.info("loaded");
		}
	}

}
